home *** CD-ROM | disk | FTP | other *** search
- #include <exec/types.h>
- #include <exec/nodes.h>
- #include <exec/resident.h>
- #include <exec/errors.h>
- #include <libraries/expansionbase.h>
- #include <libraries/configvars.h>
- #include <devices/trackdisk.h>
-
- /*
- * Set SysBase to a local variable, that loads directly from 4 when it
- * has to be reloaded
- */
- #define BASE_EXT_DECL
- #define BASE_NAME (*(void **)4)
- #include <inline/exec.h>
- #include <inline/expansion.h>
-
- #include "device.h"
-
- /*
- * in this file you find those device-commands, that are actually
- * implemented for this device. For commands, that just return true or
- * some constant look in device.c.
- */
-
- extern int lookup_cache (struct scsi_unit *su, ulong block_num, ubyte *buf);
- extern void update_cache (struct scsi_unit *su, long block_num, ubyte *buf);
- extern void invalidate_cache (struct scsi_unit *su);
- extern int AutoAutoRequest(char *l1, char *l2, char *l3, char *left, char *right);
-
- DECL_DPRINTF;
-
- #ifdef DEBUG
- #define FLASH_SCREEN() { int i; for (i=0; i < 10000; i++) *(unsigned short*)0xdff180=i;}
- #else
- #define FLASH_SCREEN()
- #endif
-
- int
- scsi_read(struct IOStdReq *io_req)
- {
- struct scsi_unit *su = (struct scsi_unit *)io_req->io_Unit;
- struct SCSICmd *sc;
- ulong length, this_length, this_offset, max_inc, data, type;
-
- DPRINTF(("read: unit %ld, type $%lx, offset %ld, length %ld",
- su->scu_unitnum, su->scu_type, io_req->io_Offset, io_req->io_Length));
-
- length = io_req->io_Length;
- data = (ulong) io_req->io_Data;
-
- #ifdef ENABLE_CACHE
- if (length == UNIT_SEC_SIZE)
- {
- if (lookup_cache (su, io_req->io_Offset / UNIT_SEC_SIZE, (ubyte *)data))
- {
- io_req->io_Actual = length;
- return 0;
- }
- }
- #endif
-
- /*
- * if the buffer is not word aligned, I have to use the unit buffer
- * and later copy the bits and bytes, argl..
- */
- if (data & 1)
- {
- data = (ulong) su->scu_buf;
- max_inc = sizeof(su->scu_buf); /* *has* to be <= DMA_MAX_TRANSFER */
- }
- else
- {
- /* 2090-DMA circuit can only handle up to 64K direct DMA, sigh.. */
- max_inc = DMA_MAX_TRANSFER;
- }
-
- this_length = length > max_inc ? max_inc : length;
- this_offset = io_req->io_Offset;
-
- /* don't care whether the medium is removable or not.. (yet:-)) */
- type = su->scu_type & ~SCU_TYPE_RMB;
-
- if (type != SCU_TYPE_DIRECT && type != SCU_TYPE_SEQUENTIAL)
- /* don't know how to access cd-roms, printers etc... */
- return IOERR_NOCMD;
-
- sc = &su->scu_scsicmd;
- sc->scsi_Flags = SCSIF_READ;
-
- /*
- * if type is sequential, AND offset is 0, then we issue a REWIND
- * before we start
- */
- if (type == SCU_TYPE_SEQUENTIAL && this_offset == 0)
- {
- ubyte *cb = su->scu_cmd;
- *cb++ = 1; /* REWIND */
- *cb++ = 0; /* wait for completion */
- *cb++ = 0;
- *cb++ = 0;
- *cb++ = 0;
- *cb = 0;
- su->scu_hmessage.scm_cmd = SCM_CMD_EXEC_SCSI;
- sc->scsi_Length = 0;
- PutGetMsg(su->scu_hmsgport, &su->scu_unit.unit_MsgPort,
- (struct Message *)&su->scu_hmessage);
- }
-
- io_req->io_Actual = 0;
-
- /*
- * this statement moved after REWIND to allow for READs with length 0
- * to rewind the tape
- */
- if (!length)
- {
- /* just abort right here.. it could be hazardrous to the DMA
- * circuit if it had to transfer 0 byte .. */
- return 0;
- }
-
- do
- {
- if (type == SCU_TYPE_DIRECT)
- {
- ubyte *cb = su->scu_cmd;
- *cb++ = 0x28;
- *cb++ = 0;
- *cb++ = 0; /* 24 + 9 exceeds 32 bit.. */
- *cb++ = this_offset >> (16 + 9); /* heavy stuff for the */
- *cb++ = this_offset >> ( 8 + 9); /* optimizer... :-))) */
- *cb++ = this_offset >> ( 9);
- *cb++ = 0;
- *cb++ = this_length >> ( 8 + 9);
- *cb++ = this_length >> ( 9);
- *cb = 0;
- }
- else /* SCU_TYPE_SEQUENTIAL */
- {
- ubyte *cb = su->scu_cmd;
- *cb++ = 0x8; /* no extended read for seq devices */
- *cb++ = 1; /* use fixed size blocks */
- *cb++ = this_length >> (16 + 9);
- *cb++ = this_length >> ( 8 + 9);
- *cb++ = this_length >> ( 9);
- *cb = 0;
- }
- su->scu_hmessage.scm_cmd = SCM_CMD_EXEC_SCSI;
- sc->scsi_Data = (UWORD *)data;
- sc->scsi_Length = this_length;
- PutGetMsg(su->scu_hmsgport, &su->scu_unit.unit_MsgPort,
- (struct Message *)&su->scu_hmessage);
-
- /* error check */
- if (su->scu_hmessage.scm_cmd != 0)
- {
- /* better not retry sequ accesses.. */
- if (type == SCU_TYPE_SEQUENTIAL)
- return su->scu_hmessage.scm_cmd;
-
- if (su->scu_errors++ > UNIT_MAX_ERRORS)
- {
- sprintf(su->scu_buf, "Unit %d had %d errors",
- su->scu_unitnum,
- su->scu_errors + UNIT_MAX_ERRORS*su->scu_errorlevel);
-
- su->scu_errors = 0;
- switch (su->scu_errorlevel ++)
- {
- case 0: AutoAutoRequest(SCSI_NAME, (char *)su->scu_buf,
- "Please safe your data!",
- "Cancel", "Cancel");
- break;
- case 1: AutoAutoRequest(SCSI_NAME, (char *)su->scu_buf,
- "Please don't use this unit anymore!",
- "I won't!", "I won't!");
- break;
- default: AutoAutoRequest(SCSI_NAME, (char *)su->scu_buf,
- "You'd better use FORMAT anyway!",
- "Yes dad!", "Yes dad!");
- break;
- }
- return su->scu_hmessage.scm_cmd;
- }
- continue; /* retry command */
- }
- /* do we have to copy (shudder, performance killer...) ?? */
- if (data == (ulong) su->scu_buf)
- /* I'm not allowed to directly increment the io_req pointer */
- CopyMem((char *)data, (char*)io_req->io_Data+io_req->io_Actual,
- this_length);
- else
- data += this_length;
-
- io_req->io_Actual += sc->scsi_Actual;
- length -= this_length;
- this_offset += this_length;
-
- this_length = length > max_inc ? max_inc : length;
- /*
- * if scsi_Actual is 0, and there is no error, I can't imagine
- * what's happening .. to prevent an infinite loop, I'll break
- * and the application should take care of this strange device..
- */
- } while (this_length && sc->scsi_Actual);
-
- #ifdef ENABLE_CACHE
- if (io_req->io_Length == UNIT_SEC_SIZE)
- update_cache (su, io_req->io_Offset / UNIT_SEC_SIZE, (ubyte*)io_req->io_Data);
- #endif
-
- return 0; /* if we get here, no errors happened.. */
- }
-
- int
- scsi_write(struct IOStdReq *io_req)
- {
- struct scsi_unit *su = (struct scsi_unit *)io_req->io_Unit;
- struct SCSICmd *sc;
- ulong length, this_length, this_offset, max_inc, data, type;
-
- DPRINTF(("write: unit %ld, type $%lx, offset %ld, length %ld",
- su->scu_unitnum, su->scu_type, io_req->io_Offset, io_req->io_Length));
-
- length = io_req->io_Length;
- data = (ulong) io_req->io_Data;
-
- if (!length)
- {
- /*
- * just abort right here.. it could be hazardrous to the DMA
- * circuit if it had to transfer 0 byte ..
- */
- io_req->io_Actual = 0;
- return 0;
- }
-
- /*
- * if the buffer is not word aligned, I have to use the unit buffer
- * and copy the bits and bytes before the transfer, argl..
- */
- if (data & 1)
- {
- data = (ulong) su->scu_buf;
- max_inc = sizeof(su->scu_buf); /* *has* to be <= DMA_MAX_TRANSFER */
- }
- else
- {
- /* 2090-DMA circuit can only handle up to 64K direct DMA, sigh.. */
- max_inc = DMA_MAX_TRANSFER;
- }
-
- this_length = length > max_inc ? max_inc : length;
- this_offset = io_req->io_Offset;
-
- /*
- * do this check before performing any actions.. if something goes
- * wrong, we end up with an invalidated cache, that's lots better
- * than pretending it's still ok..
- */
- if (io_req->io_Length != UNIT_SEC_SIZE)
- invalidate_cache (su);
-
- /* don't care whether the medium is removable or not.. (yet:-)) */
- type = su->scu_type & ~SCU_TYPE_RMB;
- if (type != SCU_TYPE_DIRECT && type != SCU_TYPE_SEQUENTIAL)
- /* don't know how to access cd-roms, printers etc... */
- return IOERR_NOCMD;
-
- sc = &su->scu_scsicmd;
- /* rewind is not a write or a read, stick to the safe option.. */
- sc->scsi_Flags = SCSIF_READ;
-
- /* if type is sequential, AND offset is 0, then we issue a REWIND
- * before we start */
- if (type == SCU_TYPE_SEQUENTIAL && this_offset==0)
- {
- ubyte *cb = su->scu_cmd;
- *cb++ = 1; /* REWIND */
- *cb++ = 0; /* wait for completion */
- *cb++ = 0;
- *cb++ = 0;
- *cb++ = 0;
- *cb = 0;
- su->scu_hmessage.scm_cmd = SCM_CMD_EXEC_SCSI;
- sc->scsi_Length = 0;
- PutGetMsg(su->scu_hmsgport, &su->scu_unit.unit_MsgPort,
- (struct Message *)&su->scu_hmessage);
- }
-
- io_req->io_Actual = 0;
-
- do
- {
- /* do we have to copy (shudder, performance killer...) ?? */
- if (data == (ulong) su->scu_buf)
- /* I'm not allowed to directly increment the io_req pointer */
- CopyMem((char*)io_req->io_Data+io_req->io_Actual,
- (char*)data, this_length);
-
- if (type == SCU_TYPE_DIRECT)
- {
- ubyte *cb = su->scu_cmd;
- *cb++ = 0x2a;
- *cb++ = 0;
- *cb++ = 0; /* 24 + 9 exceeds 32 bit.. */
- *cb++ = this_offset >> (16 + 9); /* heavy stuff for the */
- *cb++ = this_offset >> ( 8 + 9); /* optimizer... :-))) */
- *cb++ = this_offset >> ( 9);
- *cb++ = 0;
- *cb++ = this_length >> ( 8 + 9);
- *cb++ = this_length >> ( 9);
- *cb = 0;
- }
- else /* SCU_TYPE_SEQUENTIAL */
- {
- ubyte *cb = su->scu_cmd;
- *cb++ = 0xa; /* no extended write for seq devices */
- *cb++ = 1; /* use fixed size blocks */
- *cb++ = this_length >> (16 + 9);
- *cb++ = this_length >> ( 8 + 9);
- *cb++ = this_length >> ( 9);
- *cb = 0;
- }
- su->scu_hmessage.scm_cmd = SCM_CMD_EXEC_SCSI;
- sc->scsi_Data = (UWORD *)data;
- sc->scsi_Length = this_length;
- sc->scsi_Flags = SCSIF_WRITE;
- PutGetMsg(su->scu_hmsgport, &su->scu_unit.unit_MsgPort,
- (struct Message *)&su->scu_hmessage);
-
- /* error check */
- if (su->scu_hmessage.scm_cmd != 0)
- {
- /* better not retry sequ accesses.. */
- if (type == SCU_TYPE_SEQUENTIAL)
- return su->scu_hmessage.scm_cmd;
-
- if (su->scu_errors++ > UNIT_MAX_ERRORS)
- {
- sprintf(su->scu_buf, "Unit %d had %d errors",
- su->scu_unitnum,
- su->scu_errors + UNIT_MAX_ERRORS*su->scu_errorlevel);
-
- su->scu_errors = 0;
- switch (su->scu_errorlevel ++)
- {
- case 0: AutoAutoRequest(SCSI_NAME, (char *)su->scu_buf,
- "Please safe your data!",
- "Cancel", "Cancel");
- break;
- case 1: AutoAutoRequest(SCSI_NAME, (char *)su->scu_buf,
- "Please don't use this unit anymore!",
- "I won't!", "I won't!");
- break;
- default: AutoAutoRequest(SCSI_NAME, (char *)su->scu_buf,
- "You'd better use FORMAT anyway!",
- "Yes dad!", "Yes dad!");
- break;
- }
- return su->scu_hmessage.scm_cmd;
- }
- continue; /* retry command */
- }
-
- if (data != (ulong) su->scu_buf)
- data += this_length;
-
- io_req->io_Actual += sc->scsi_Actual;
- length -= this_length;
- this_offset += this_length;
-
- this_length = length > max_inc ? max_inc : length;
- /*
- * if scsi_Actual is 0, and there is no error, I can't imagine
- * what's happening .. to prevent an infinite loop, I'll break
- * and the application should take care of this strange device..
- */
- } while (this_length && sc->scsi_Actual);
-
- #ifdef ENABLE_CACHE
- if (io_req->io_Length == UNIT_SEC_SIZE)
- update_cache (su, io_req->io_Offset / UNIT_SEC_SIZE, (ubyte*)io_req->io_Data);
- #endif
-
- return 0; /* if we get here, no errors happened.. */
- }
-
- int
- scsi_format(struct IOStdReq *io_req)
- {
- /*
- * "could" do some checking, whether the parameters meet certain
- * tougher criteria than for write, but who cares, my write can
- * even cope with odd-aligned data, so what ?
- */
- return scsi_write(io_req);
- }
-
- /*
- * this is one of the easiest commands of the whole device... the entire
- * device structure is laid out for this to be implemented as good as
- * possible:-))
- */
- int
- scsi_direct(struct IOStdReq *io_req)
- {
- struct scsi_msg sm;
- struct scsi_unit *su;
-
- su = (struct scsi_unit *)io_req->io_Unit;
- sm.scm_cmd = SCM_CMD_EXEC_SCSI;
- sm.scm_unit = su->scu_unitnum;
- sm.scm_message.mn_ReplyPort = &su->scu_unit.unit_MsgPort;
- sm.scm_scsi_cmd = (struct SCSICmd *)io_req->io_Data;
-
- PutGetMsg(su->scu_hmsgport, &su->scu_unit.unit_MsgPort,
- (struct Message *)&sm);
- DPRINTF(("scsi-direct: unit %ld, result %ld", su->scu_unitnum, sm.scm_cmd));
- return sm.scm_cmd;
- }
-
- int
- scsi_protstatus(struct IOStdReq *io_req)
- {
- struct scsi_unit *su = (struct scsi_unit *)io_req->io_Unit;
- struct SCSICmd *sc;
- ulong sense_buf;
- ubyte *cb;
-
- sc = &su->scu_scsicmd;
- sc->scsi_Flags = SCSIF_READ;
- cb = su->scu_cmd;
- *cb++ = 0x1A; /* MODE SENSE */
- *cb++ = *cb++ = *cb++ = 0;
- *cb++ = 4; /* allocated length */
- *cb = 0;
-
- su->scu_hmessage.scm_cmd = SCM_CMD_EXEC_SCSI;
- sense_buf = 0;
- sc->scsi_Data = (UWORD *)&sense_buf;
- sc->scsi_Length = 4;
- PutGetMsg(su->scu_hmsgport, &su->scu_unit.unit_MsgPort,
- (struct Message *)&su->scu_hmessage);
-
- io_req->io_Actual = sense_buf & 0x00008000 ? 1 : 0; /* WP bit */
- return su->scu_hmessage.scm_cmd;
- }
-